#region Namespaces

using Vibstudio.X4NET.Xml.Linq;
using Vibstudio.X4NET.Xml.XPath;

#endregion

namespace Vibstudio.X4NET.Xml.Navigation
{
    public class XNavigator
    {
        public static XmlKeyValuePairCollection Parse(string uri)
        {
            return Parse(uri,
                         Defaults.XPathRoot,
                         true,
                         true,
                         SearchCriterion.None,
                         string.Empty);
        }

        public static XmlKeyValuePairCollection Parse(string uri, bool includingEmptyValues)
        {
            return Parse(uri,
                         Defaults.XPathRoot,
                         includingEmptyValues,
                         true,
                         SearchCriterion.None,
                         string.Empty);
        }

        public static XmlKeyValuePairCollection Parse(string uri, bool includingEmptyValues, bool includingAttributes)
        {
            return Parse(uri,
                         Defaults.XPathRoot,
                         includingEmptyValues,
                         includingAttributes,
                         SearchCriterion.None,
                         string.Empty);
        }

        public static XmlKeyValuePairCollection Parse(string uri, bool includingEmptyValues, bool includingAttributes, bool positional, bool textual)
        {
            return Parse(uri,
                         Defaults.XPathRoot,
                         includingEmptyValues,
                         includingAttributes,
                         SearchCriterion.None,
                         string.Empty,
                         positional,
                         textual);
        }

        public static XmlKeyValuePairCollection Parse(string uri, string xpath)
        {
            return Parse(uri,
                         xpath,
                         true,
                         true,
                         SearchCriterion.None,
                         string.Empty);
        }

        public static XmlKeyValuePairCollection Parse(string uri, string xpath, bool includingEmptyValues)
        {
            return Parse(uri,
                         xpath,
                         includingEmptyValues,
                         true,
                         SearchCriterion.None,
                         string.Empty);
        }

        public static XmlKeyValuePairCollection Parse(string uri, SearchCriterion criteria, string searchValue)
        {
            return Parse(uri,
                         Defaults.XPathRoot,
                         true,
                         true,
                         criteria,
                         searchValue);
        }

        public static XmlKeyValuePairCollection Parse(string uri, bool includingEmptyValues, SearchCriterion criteria, string searchValue)
        {
            return Parse(uri,
                         Defaults.XPathRoot,
                         includingEmptyValues,
                         true,
                         criteria,
                         searchValue);
        }

        public static XmlKeyValuePairCollection Parse(string uri,
                                                      string xpath,
                                                      bool includingEmptyValues,
                                                      bool includingAttributes,
                                                      SearchCriterion criteria,
                                                      string searchValue,
                                                      bool positional = true,
                                                      bool textual = false)
        {
            return Parse(XDocument.Load(uri),
                         xpath,
                         includingEmptyValues,
                         includingAttributes,
                         criteria,
                         searchValue,
                         positional,
                         textual);
        }

        public static XmlKeyValuePairCollection Parse(XDocument document,
                                                      bool includingEmptyValues = true,
                                                      bool includingAttributes = true,
                                                      bool positional = true,
                                                      bool textual = false)
        {
            return Parse(document,
                         Defaults.XPathRoot,
                         includingEmptyValues,
                         includingAttributes,
                         SearchCriterion.None,
                         string.Empty,
                         positional,
                         textual);
        }

        public static XmlKeyValuePairCollection Parse(XDocument document,
                                                      string xpath,
                                                      bool includingEmptyValues,
                                                      bool includingAttributes,
                                                      SearchCriterion criteria,
                                                      string searchValue,
                                                      bool positional = true,
                                                      bool textual = false)
        {
            XmlKeyValuePairCollection collection = new XmlKeyValuePairCollection { XPaths = document.ExtractXPaths(positional, textual, includingAttributes, xpath) };

            StringsSeeker seeker = new StringsSeeker(criteria);

            foreach (string currXPath in collection.XPaths)
            {
                XmlKeyValuePair valuePair;
                if (document.TryParseElement(currXPath, out valuePair))
                {
                    FixCollection(collection, valuePair, seeker, searchValue, includingEmptyValues);
                }
                else
                {
                    if (document.TryParseAttribute(currXPath, out valuePair))
                    {
                        FixCollection(collection, valuePair, seeker, searchValue, includingEmptyValues);
                    }
                }
            }

            return collection;
        }

        #region Helpers

        private static void FixCollection(XmlKeyValuePairCollection collection,
                                          XmlKeyValuePair valuePair,
                                          StringsSeeker seeker,
                                          string searchValue,
                                          bool includingEmptyValues)
        {
            // Valori nulli non ammessi
            if (includingEmptyValues == false && string.IsNullOrEmpty(valuePair.Value))
            {
                return;
            }

            if (seeker.IsExpectedString(valuePair.Value, searchValue))
            {
                collection.Add(valuePair);
            }
        }

        #endregion
    }
}